package com.youxin.cpcenter.service.impl;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.youxin.busfoundation.Consts;
import com.youxin.busfoundation.bean.BusinessMessages;
import com.youxin.busfoundation.bean.ResponseObject;
import com.youxin.busfoundation.bean.ent.RequestEntMemberIdentifyCapitalBean;
import com.youxin.busfoundation.bean.login.UserInfo;
import com.youxin.busfoundation.common.BusinessDataException;
import com.youxin.busfoundation.common.LoginAuth;
import com.youxin.busfoundation.common.redis.RedisOperator;
import com.youxin.busfoundation.config.WxBeanConfig;
import com.youxin.busfoundation.config.ZfbBeanConfig;
import com.youxin.busfoundation.enums.OrderPayStatusEnums;
import com.youxin.busfoundation.enums.OrderPayTypeEnums;
import com.youxin.busfoundation.enums.ProductsCouponEnums;
import com.youxin.busfoundation.utils.weixin.PayCommonUtil;
import com.youxin.busfoundation.utils.weixin.WXPayUtil;
import com.youxin.cpcenter.bean.RequestOrderInfoBean;
import com.youxin.cpcenter.bean.RequestTradeQueryBean;
import com.youxin.cpcenter.dao.TbOrderInfoMapper;
import com.youxin.cpcenter.model.TbMemberInfo;
import com.youxin.cpcenter.model.TbOrderInfo;
import com.youxin.cpcenter.service.CapitalService;
import com.youxin.cpcenter.service.EntMemberIdentifyCapitalService;
import com.youxin.cpcenter.service.TransactionService;
import com.youxin.foundation.utils.AmountUtils;
import com.youxin.foundation.utils.DateUtil;
import com.youxin.foundation.utils.HttpUtil;
import com.youxin.foundation.utils.JsonUtils;
import com.youxin.foundation.utils.StringUtils;

@Service("transactionService")
public class TransactionServiceImpl implements TransactionService {
	protected static org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(TransactionServiceImpl.class);
	@Autowired
	private TbOrderInfoMapper tbOrderInfoMapper;
	@Autowired
	private EntMemberIdentifyCapitalService entMemberIdentifyCapitalService;
	@Autowired
	private CapitalService capitalService;

	/**
	 * 支付回调成功后更新订单状态
	 */
	@Transactional(propagation = Propagation.REQUIRED)
	public String procesNotifyTransaction(TbOrderInfo model) {
		try {
			if (null == model) {
				throw new BusinessDataException("对象为空!");
			}
			// 查询是否存在redis并已处理
			String orderSn = RedisOperator.getOrderPayStatus(model.getOrderSn());
			if (!StringUtils.isNullOrEmpty(orderSn)) {
				return BusinessMessages.SUCCESS_MESSAGE;
			}
			// 在数据库中查找订单号对应的订单，并将其金额与数据库中的金额对比，若对不上，也为异常通知
			TbOrderInfo orderInfo = tbOrderInfoMapper.selectByPrimaryOrderSn(model.getOrderSn());
			if (orderInfo == null) {
				model.setPayStatus(OrderPayStatusEnums.PayFaillure.getValue());
				throw new BusinessDataException("订单号：" + model.getOrderSn() + "，查无此订单!");
			}

			// 数据库查询出订单已经处理成功，不处理回调请求
			if (orderInfo.getPayStatus().intValue() == OrderPayStatusEnums.PaySuccess.getValue()) {
				return BusinessMessages.SUCCESS_MESSAGE;
			}
			
			int orderType=orderInfo.getOrderType().intValue();
			if(!(orderType==OrderPayTypeEnums.VIP.getIndex()
					||orderType==OrderPayTypeEnums.PTVIP.getIndex()
					||orderType==OrderPayTypeEnums.CZJJ.getIndex()))
			{
				throw new BusinessDataException("不支持的支付类型");
			}
			
			model.setId(orderInfo.getId());
			model.setUpdateTime(DateUtil.getDateForInt());

			// 非成功状态的其它失败状态直接更新相应失败状态
			if (model.getPayStatus().intValue() == OrderPayStatusEnums.PayFaillure.getValue()
					|| model.getPayStatus().intValue() == OrderPayStatusEnums.PayClose.getValue()) {
				tbOrderInfoMapper.updatePayStatusByOrderSn(model);
				logger.warn("订单号：" + model.getOrderSn() + "，支付失败，支付状态："
						+ OrderPayStatusEnums.valueOf(model.getPayStatus()));
				return BusinessMessages.SUCCESS_MESSAGE;
			}

			// 订单金额与实际支付金额比较 ***********本地调试请注释以下代码，实际支付金额为测试的一分钱 **************
			/*
			 * if (!StringUtils.isNullOrEmpty(model.getPayAmount().toString())
			 * && !orderInfo.getOrderAmount().equals(model.getPayAmount())) {
			 * model.setPayStatus(OrderPayStatusEnums.PayFaillure.getValue());
			 * tbOrderInfoMapper.updateByPrimaryKeySelective(model);
			 * logger.warn("订单号："+model.getOrderSn() +
			 * "，订单金额："+orderInfo.getOrderAmount()+"与支付金额:"+model.getPayAmount()
			 * +"不一致!"); return BusinessMessages.SUCCESS_MESSAGE; }
			 */

			// 支付状态为成功
			model.setPayStatus(OrderPayStatusEnums.PaySuccess.getValue());
			int rowEffected = tbOrderInfoMapper.updatePayStatusByOrderSn(model);
			if (rowEffected == 0) {
				logger.warn("更新失败rowEffected=0:" + String.valueOf(JsonUtils.objectToFasterxmlJsonString(model)));
				return BusinessMessages.SUCCESS_MESSAGE;
			}

			// 会员升级 ,升级完后不处理下面流程，直接返回
			if (orderInfo.getOrderType().equals(OrderPayTypeEnums.VIP.getIndex())
					|| orderInfo.getOrderType().equals(OrderPayTypeEnums.PTVIP.getIndex())) {
				capitalService.recharge(orderInfo);
				return BusinessMessages.SUCCESS_MESSAGE;
			}
			
			// 添加金券
			RequestEntMemberIdentifyCapitalBean bean = new RequestEntMemberIdentifyCapitalBean();
			bean.setEntIdentifyId(orderInfo.getEntIdentifyId());
			bean.setCoupon(orderInfo.getPoint());
			entMemberIdentifyCapitalService.increaseCoupon(bean);
			// 成功保存订单到redis
			RedisOperator.saveOrderPayStatus(model.getOrderSn());
		} catch (Exception e) {
			logger.warn("订单号：" + model.getOrderSn() + ",系统异常，error=" + e);
			throw new BusinessDataException(BusinessMessages.SYSTEM_ERROR);
		}
		return BusinessMessages.SUCCESS_MESSAGE;
	}

	/**
	 * 处理支付请求记录并保存
	 */
	@Override
	public String procesPayTransaction(RequestOrderInfoBean requestBean, TbMemberInfo memberInfo, String orderSn) {
		try {
			if (null != requestBean && null != memberInfo && null != orderSn) {
				UserInfo userInfo = LoginAuth.getUserInfo();
				// 存储支付请求数据
				TbOrderInfo model = new TbOrderInfo();
				BeanUtils.copyProperties(requestBean, model);
				model.setMemberUid(memberInfo.getUid());
				model.setMemberId(memberInfo.getId());
				model.setOrderSn(orderSn);
				// 金额
				BigDecimal ta = new BigDecimal(requestBean.getProductId());
				// 设置小数位数，第一个变量是小数位数，第二个变量是取舍方法(四舍五入)
				ta = ta.setScale(2, BigDecimal.ROUND_HALF_UP);
				model.setOrderAmount(ta);
				// 点券
				if (requestBean.getOrderType().equals(OrderPayTypeEnums.CZJJ.getIndex())) {
					String point = ProductsCouponEnums.getName(requestBean.getProductId());
					BigDecimal dPoint = new BigDecimal(point);
					// 设置小数位数，第一个变量是小数位数，第二个变量是取舍方法(四舍五入)
					dPoint = dPoint.setScale(2, BigDecimal.ROUND_HALF_UP);
					model.setPoint(dPoint);
				}
				model.setOrderType(requestBean.getOrderType());
				// 付款状态：0-待付款 1-未付款 2-已付款 3-支付失败 4-已关闭
				model.setPayStatus(OrderPayStatusEnums.WaitPay.getValue());
				model.setPayTime(DateUtil.getDateForInt());
				model.setAddTime(DateUtil.getDateForInt());
				model.setUpdateTime(DateUtil.getDateForInt());
				model.setEntIdentifyId(userInfo.getEntIdentifyId());
				model.setEntMemberId(userInfo.getEntMemberId());
				tbOrderInfoMapper.insertSelective(model);
			} else {
				throw new BusinessDataException(BusinessMessages.SYSTEM_ERROR);
			}
		} catch (Exception e) {
			throw new BusinessDataException(BusinessMessages.FAILURE_MESSAGE);
		}
		return BusinessMessages.SUCCESS_MESSAGE;
	}

	/**
	 * 
	 * @Title: alipayTradeQuery @Description: 阿里支付交易结果查询 @param @param
	 * orderSn @param @param platformNo @param @return @return
	 * ResponseObject @throws
	 */
	public ResponseObject alipayTradeQuery(String orderSn) {
		String result = null;
		try {
			// 获得初始化的AlipayClient
			AlipayClient alipayClient = new DefaultAlipayClient(ZfbBeanConfig.getConfig().getOpenApiDomain(),
					ZfbBeanConfig.getConfig().getAppid(), ZfbBeanConfig.getConfig().getPrivateKey(), "json", "utf-8",
					ZfbBeanConfig.getConfig().getAlipayPublicKey(), "RSA2");
			// 设置请求参数
			AlipayTradeQueryRequest alipayRequest = new AlipayTradeQueryRequest();
			alipayRequest.setBizContent("{\"out_trade_no\":\"" + orderSn + "\"}");
			// 请求
			result = alipayClient.execute(alipayRequest).getBody();
		} catch (AlipayApiException e) {
			return ResponseObject.userFailure("支付宝订单查询构造表单失败" + e);
		}
		return ResponseObject.successObject(result);
	}

	/**
	 * 
	 * @Title: wxTradeQuery @Description: 微信交易结果查询 @param @param
	 * requestBean @param @return @return ResponseObject @throws
	 */
	public ResponseObject wxTradeQuery(RequestTradeQueryBean requestBean) {
		Map<String, String> result = null;
		try {
			HashMap<String, String> data = new HashMap<String, String>();
			data.put("out_trade_no", requestBean.getOrderSn());
			/* data.put("transaction_id", requestBean.getPlatformNo()); */
			// 账号信息
			String appid = WxBeanConfig.getConfig().getAppId(); // appid
			String mch_id = WxBeanConfig.getConfig().getMchId(); // 商业号
			// 生成随机字符串
			String currTime = PayCommonUtil.getCurrTime();
			String strTime = currTime.substring(8, currTime.length());
			String strRandom = PayCommonUtil.buildRandom(4) + "";
			String nonce_str = strTime + strRandom;
			data.put("appid", appid);// 公众账号ID
			data.put("mch_id", mch_id);// 商户号
			data.put("nonce_str", nonce_str);// 随机字符串
			data.put("sign_type", Consts.MD5);
			data.put("sign", WXPayUtil.generateSignature(data, WxBeanConfig.getConfig().getApiKey()));
			String respXml = HttpUtil.postData(WxBeanConfig.getConfig().getOrderQueryUrl(), WXPayUtil.mapToXml(data));
			result = WXPayUtil.processResponseXml(respXml, WxBeanConfig.getConfig().getApiKey());
		} catch (Exception e) {
			return ResponseObject.userFailure("微信支付查询交易结果失败" + e);
		}
		return new ResponseObject(result);
	}

	/**
	 * @Title: queryWx @Description: 微信支付 @param @param orderSn @param @param
	 * platformNo @param @param model @return void @throws
	 */
	public TbOrderInfo queryWx(String orderSn) {
		TbOrderInfo model = new TbOrderInfo();
		model.setPayStatus(OrderPayStatusEnums.WaitPay.getValue());
		RequestTradeQueryBean bean = new RequestTradeQueryBean();
		bean.setOrderSn(orderSn);
		ResponseObject rs = wxTradeQuery(bean);
		if (rs.getCode() == 0) {
			Map<String, Object> obj = JsonUtils.objectToMapObject(rs.getData());
			String msg = obj.get("result_code").toString();
			if (Consts.FAIL_CAPITAL.equalsIgnoreCase(msg)) {
				model.setRemark(obj.toString());
				model.setPayStatus(OrderPayStatusEnums.PayFaillure.getValue());
				logger.warn("微信交易失败1，返回信息：" + obj.toString());
			} else if (Consts.SUCCESS_CAPITAL.equalsIgnoreCase(msg)) {
				String code = obj.get("trade_state").toString();
				/**
				 * SUCCESS—支付成功 REFUND—转入退款 NOTPAY—未支付 CLOSED—已关闭
				 * REVOKED—已撤销（刷卡支付） USERPAYING--用户支付中
				 * PAYERROR--支付失败(其他原因，如银行返回失败)
				 */
				if (code.equalsIgnoreCase(Consts.SUCCESS_CAPITAL)) {
					String transaction_id = obj.get("transaction_id").toString();
					String totalAmount = obj.get("total_fee").toString();
					BigDecimal pa = new BigDecimal(AmountUtils.changeF2Y(totalAmount));
					model.setPlatformNo(transaction_id);
					model.setPayStatus(OrderPayStatusEnums.PaySuccess.getValue());
					model.setRemark(msg);
					model.setPayAmount(pa);
				} else if ("PAYERROR".equalsIgnoreCase(code) || "CLOSED".equalsIgnoreCase(code)
						|| "REVOKED".equalsIgnoreCase(code)) {
					model.setRemark(obj.toString());
					model.setPayStatus(OrderPayStatusEnums.PayFaillure.getValue());
					logger.warn("微信交易失败2，返回信息：" + obj.toString());
				}
			} else {
				model.setRemark(obj.toString());
				logger.warn("微信交易失败3，返回信息：" + obj.toString());
			}
			model.setOrderSn(orderSn);
		} else {
			model.setOrderSn(orderSn);
			logger.warn("微信查询失败，msg：" + rs.getMsg());
		}
		return model;
	}

	/**
	 * @Title: queryAlipay @Description: 支付宝 @param @param orderSn @param @param
	 * platformNo @param @param model @return void @throws
	 */
	public TbOrderInfo queryAlipay(String orderSn) {
		TbOrderInfo model = new TbOrderInfo();
		model.setPayStatus(OrderPayStatusEnums.WaitPay.getValue());
		ResponseObject rs = alipayTradeQuery(orderSn);
		if (rs.getCode() == 0) {
			Map<String, Object> map = JsonUtils.objectToMapObject(rs.getData());
			Object alipayTradeQueryRes = map.get("alipay_trade_query_response");
			Map<String, Object> obj = JsonUtils.objectToMapObject(alipayTradeQueryRes);
			String code = obj.get("code").toString();
			String msg = obj.get("msg").toString();
			String tradeStatus = obj.get("trade_status").toString();
			if (code.equals("10000")) {
				String transaction_id = obj.get("trade_no").toString();
				String totalAmount = obj.get("total_amount").toString();
				BigDecimal pa = new BigDecimal(totalAmount);
				model.setPlatformNo(transaction_id);
				/**
				 * 交易状态：WAIT_BUYER_PAY（交易创建，等待买家付款）、TRADE_CLOSED（未付款交易超时关闭，或支付完成后全额退款）、TRADE_SUCCESS（交易支付成功）、TRADE_FINISHED（交易结束，不可退款）
				 */
				if ("TRADE_SUCCESS".equalsIgnoreCase(tradeStatus) || "TRADE_FINISHED".equalsIgnoreCase(tradeStatus)) {
					model.setPayStatus(OrderPayStatusEnums.PaySuccess.getValue());
				} else if ("TRADE_CLOSED".equalsIgnoreCase(tradeStatus)) {
					model.setPayStatus(OrderPayStatusEnums.PayClose.getValue());
				}
				model.setRemark(msg);
				model.setPayAmount(pa);
			} else {
				model.setRemark(obj.toString());
				model.setPayStatus(OrderPayStatusEnums.WaitPay.getValue());
				logger.warn("支付宝交易失败，返回信息：" + obj.toString());
			}
			model.setOrderSn(orderSn);
		} else {
			model.setOrderSn(orderSn);
			logger.warn("支付宝查询失败，msg：" + rs.getMsg());
		}
		return model;
	}

	/**
	 * 支付结果返回前端
	 */
	@Override
	public ResponseObject procesResponseStatus(TbOrderInfo model) {
		Map<Object, Object> rs = new HashMap<>();
		if (null != model) {
			rs.put("pay_status", model.getPayStatus());
			rs.put("order_sn", model.getOrderSn());
		}
		return ResponseObject.successObject(rs);
	}
}
